/*=======================================================

    HCView V1.0
    文档内对象样式管理单元
    作者：荆通(18114532@qq.com)
    QQ群：649023932

=======================================================*/

import { THCCanvas } from "../hcl/Graphics.js";
import { TList, TObject } from "../hcl/System.js";
import { THCState, HC } from "./HCCommon.js";
import { THCParaStyle } from "./HCParaStyle.js";
import { THCTextStyle } from "./HCTextStyle.js";
import { TXmlNode } from "../hcl/XmlDocument.js";

class TUpdateInfo {
    constructor() {
        this.RePaint = false;
        this.ReCaret = false;
        this.ReStyle = false;
        this.ReScroll = false;
        this.Selecting = false;
        this.DragingSelected = false;
    }
}

class THCStateDictionary {
    constructor() {
        this.State = THCState.Loading;
        this.Count = 0;
    }
}

class THCStates {
    constructor() {
        this.FStates = new TList();
    }

    _deleteState(index) {
        this.FStates.delete(index);
    }

    _getStateIndex(state) {
        for (let i = 0; i < this.FStates.Count; i++) {
            if (this.FStates[i].State === state)
                return i;
        }

        return -1;
    }

    Include(state) {
        let vIndex = this._getStateIndex(state);
        if (vIndex >= 0)
            this.FStates[vIndex].Count++;
        else {
            let vStateDic = new THCStateDictionary();
            vStateDic.State = state;
            vStateDic.Count = 1;
            this.FStates.add(vStateDic);
        }
    }

    Exclude(state)
    {
        let vIndex = this._getStateIndex(state);
        if (vIndex >= 0) {
            if (this.FStates[vIndex].Count > 1)
                this.FStates[vIndex].Count--;
            else
                this._deleteState(vIndex);
        }
    }

    Contain(state) {
        return this._getStateIndex(state) >= 0;
    }
}

export class THCStyle extends TObject {
    constructor(defTextStyle = false, defParaStyle = false) {
        super();
        this.FTempCanvas = this.CreateStyleCanvas();
        this.FTempStyleNo = THCStyle.Null;
        this.FBackgroundColor = "#ffffff";
        this.FSelColor = "#a6caf0";
        this.FLineSpaceMin = 8;
        this.FShowParaLastMark = true;
        this.FDrawActiveDomainRegion = true;
        this.FDrawHotDomainRegion = true;
        this.FFormatVersion = 2;
        this.FStates = new THCStates();
        this.FUpdateInfo = new TUpdateInfo();
        this.FDefaultTextStyle = new THCTextStyle();
        this.FDefaultTextStyle.ApplyStyle(this.FTempCanvas);
        this.FTextStyles = new TList();
        this.FParaStyles = new TList();

        if (defTextStyle)
            this.NewDefaultTextStyle();

        if (defParaStyle)
            this.NewDefaultParaStyle();

        this.FOnInvalidateRect = null;
    }

    SetShowParaLastMark(val) {
        if (this.FShowParaLastMark != val) {
            this.FShowParaLastMark = val;
            this.UpdateInfoRePaint();
        }
    }

    Initialize() {
        this.FTextStyles.removeRange(1, this.FTextStyles.count - 1);
        this.FParaStyles.removeRange(1, this.FParaStyles.count - 1);
    }

    UpdateInfoRePaint() {
        this.FUpdateInfo.RePaint = true;
    }

    UpdateInfoReStyle() {
        this.FUpdateInfo.ReStyle = true;
    }

    UpdateInfoReScroll() {
        this.FUpdateInfo.ReScroll = true;
    }

    UpdateInfoReCaret(caretStyle = true) {
        this.FUpdateInfo.ReCaret = true;
        this.FUpdateInfo.ReStyle = caretStyle;
    }

    AddTextStyle(textStyle) {
        this.FTextStyles.add(textStyle);
        return this.FTextStyles.count - 1;
    }

    CreateStyleCanvas() {
        let vH5Canvas = document.createElement("canvas");
        let vContext = vH5Canvas.getContext("2d");
        return new THCCanvas(vContext);
    }

    DestroyStyleCanvas(hclCanvas) {
        hclCanvas.h5context.canvas = null;
    }

    NewDefaultTextStyle() {
        let vTextStyle = new THCTextStyle();
        this.FTextStyles.add(vTextStyle);
        vTextStyle.ApplyStyle(this.TempCanvas);
        return this.FTextStyles.count - 1;
    }

    NewDefaultParaStyle() {
        let vParaStyle = new THCParaStyle();
        this.FParaStyles.add(vParaStyle);
        return this.FParaStyles.count - 1;
    }

    GetStyleNo(textStyle, createIfNull) {
        let vResult = -1;
        for (let i = 0; i <= this.FTextStyles.count - 1; i++) {
            if (this.FTextStyles[i].EqualsEx(textStyle)) {
                vResult = i;
                return vResult;
            }
        }

        if (createIfNull && (vResult < 0)) {
            let vTextStyle = new THCTextStyle();
            vTextStyle.AssignEx(textStyle);
            this.FTextStyles.add(vTextStyle);
            vResult = this.FTextStyles.count - 1;
        }

        return vResult;
    }

    GetParaNo(paraStyle, createIfNull) {
        let vResult = -1;
        for (let i = 0; i <= this.FParaStyles.count - 1; i++) {
            if (this.FParaStyles[i].EqualsEx(paraStyle)) {
                vResult = i;
                return vResult;
            }
        }

        if (createIfNull && (vResult < 0)) {
            let vParaStyle = new THCParaStyle();
            vParaStyle.AssignEx(paraStyle);
            this.FParaStyles.add(vParaStyle);
            vResult = this.FParaStyles.count - 1;
        }

        return vResult;
    }

    ApplyTempStyle(val, scale = 1) {
        if (this.FTempStyleNo != val) {
            this.FTempStyleNo = val;
            if (val > THCStyle.Null)
                this.FTextStyles[val].ApplyStyle(this.FTempCanvas, scale);
        }
    }

    SaveParaStyles(stream) {
        let vCount = this.FParaStyles.count;
        stream.writeInt32(vCount);
        for (let i = 0; i <= this.FParaStyles.count - 1; i++)
            this.FParaStyles[i].SaveToStream(stream);
    }

    SaveTextStyles(stream) {
        let vCount = this.TextStyles.count;
        stream.writeInt32(vCount);
        for (let i = 0; i <= this.FTextStyles.count - 1; i++)
            this.FTextStyles[i].SaveToStream(stream);
    }

    SaveToStream(stream) {
        let vBegPos = stream.position;
        stream.writeUInt64(vBegPos);

        stream.writeByte(this.FFormatVersion);
        this.SaveParaStyles(stream);
        this.SaveTextStyles(stream);

        let vEndPos = stream.position;
        stream.position = vBegPos;
        vBegPos = vEndPos - vBegPos - 8;

        stream.writeUInt64(vBegPos);
        stream.position = vEndPos;
    }

    LoadParaStyles(stream, fileVersion) {
        this.FParaStyles.clear();
        let vStyleCount = stream.readInt32();
        for (let i = 0; i <= vStyleCount - 1; i++)
            this.FParaStyles[this.NewDefaultParaStyle()].LoadFromStream(stream, fileVersion);
    }

    LoadTextStyles(stream, fileVersion) {
        this.FTextStyles.clear();
        let vStyleCount = stream.readInt32();

        for (let i = 0; i <= vStyleCount - 1; i++)
            this.FTextStyles[this.NewDefaultTextStyle()].LoadFromStream(stream, fileVersion);
    }

    LoadFromStream(stream, fileVersion) {
        stream.readInt64();  // let vDataSize = 
        if (fileVersion > 33)
            this.FFormatVersion = stream.readByte();
        else
            this.FFormatVersion = 1;

        this.LoadParaStyles(stream, fileVersion);
        this.LoadTextStyles(stream, fileVersion);
    }

    GetHtmlFileTempName(reset = false) {
        if (reset)
            this.FHtmlFileTempName = 0;
        else
            this.FHtmlFileTempName++;

        return this.FHtmlFileTempName.toString();
    }

    ToCSS() {
        let vResult = "<style type=\"text/css\">";
        for (let i = 0; i < this.FTextStyles.count; i++) {
            vResult = vResult + HC.sLineBreak + "a.fs" + i.toString() + " {";
            vResult = vResult + this.FTextStyles[i].ToCSS() + " }"; 
        }

        // 注意单倍行间距，文本底色不为白色也不透明时会造成字符看起来叠加的问题
        for (let i = 0; i < this.FParaStyles.count; i++) {
            vResult += HC.sLineBreak + "p.ps" + i.toString() + " {";
            vResult += this.FParaStyles[i].ToCSS() + " }";
        }

        return vResult + HC.sLineBreak + "</style>";
    }

    ToXml(node) {
        node.SetAttribute("fscount", this.FTextStyles.count.toString());
        node.SetAttribute("pscount", this.FParaStyles.count.toString());
        node.SetAttribute("fmtver", this.FFormatVersion.toString());

        let vNode = TXmlNode.Create("textstyles");

        let vStyleNode;
        for (let i = 0; i < this.FTextStyles.count; i++) {
            vStyleNode = TXmlNode.Create("ts");
            this.FTextStyles[i].ToXml(vStyleNode);
            vNode.AppendChild(vStyleNode);
        }
        node.AppendChild(vNode);

        vNode = TXmlNode.Create("parastyles", "");
        let vParaNode;
        for (let i = 0; i < this.FParaStyles.count; i++) {
            vParaNode = TXmlNode.Create("ps");
            this.FParaStyles[i].ToXml(vParaNode);
            vNode.AppendChild(vParaNode);
        }
        node.AppendChild(vNode);
    }

    ParseXml(aNode) {
        // for (int i = 0; i <= aNode.ChildNodes.count - 1; i++)
        // {
        //     if (aNode.ChildNodes[i].Name == "textstyles")
        //     {
        //         FTextStyles.Clear();
        //         XmlElement vNode = aNode.ChildNodes[i] as XmlElement;
        //         for (int j = 0; j <= vNode.ChildNodes.count - 1; j++)
        //             FTextStyles[this.NewDefaultTextStyle()].ParseXml(vNode.ChildNodes[j] as XmlElement);
        //     }
        //     else
        //     if (aNode.ChildNodes[i].Name == "parastyles")
        //     {
        //         FParaStyles.Clear();
        //         XmlElement vNode = aNode.ChildNodes[i] as XmlElement;
        //         for (int j = 0; j <= vNode.ChildNodes.count - 1; j++)
        //             FParaStyles[this.NewDefaultParaStyle()].ParseXml(vNode.ChildNodes[j] as XmlElement);
        //     }
        // }
    }

    InvalidateRect(rect) {
        if (this.FOnInvalidateRect != null)
            this.FOnInvalidateRect(rect);
    }

    get DefaultTextStyle() {
        return this.FDefaultTextStyle;
    }

    get TextStyles() {
        return this.FTextStyles;
    }

    set TextStyle(val) {
        this.FTextStyles = val;
    }

    get ParaStyles() {
        return this.FParaStyles;
    }

    set ParaStyles(val) {
        this.FParaStyles = val;
    }

    get BackgroundColor() {
        return this.FBackgroundColor;
    }
    
    set BackgroundColor(val) {
        this.FBackgroundColor = val;
    }

    get SelColor() {
        return this.FSelColor;
    }

    set SelColor(val) {
        this.FSelColor = val;
    }

    get LineSpaceMin() {
        return this.FLineSpaceMin;
    }

    set LineSpaceMin(val) {
        this.FLineSpaceMin = val;
    }

    get TempStyleNo() {
        return this.FTempStyleNo;
    }

    get TempCanvas() {
        return this.FTempCanvas;
    }

    get UpdateInfo() {
        return this.FUpdateInfo;
    }

    get DrawActiveDomainRegion() {
        return this.FDrawActiveDomainRegion;
    }

    set DrawActiveDomainRegion(val) {
        this.FDrawActiveDomainRegion = val;
    }

    get DrawHotDomainRegion() {
        return this.FDrawHotDomainRegion;
    }
    
    set DrawHotDomainRegion(val) {
        this.FDrawHotDomainRegion = val;
    }

    get ShowParaLastMark() {
        return this.FShowParaLastMark;
    }

    set ShowParaLastMark(val) {
        this.SetShowParaLastMark(val);
    }

    get States() {
        return this.FStates;
    }

    get FormatVersion() {
        return this.FFormatVersion;
    }

    get OnInvalidateRect() {
        return this.FOnInvalidateRect;
    }

    set OnInvalidateRect(val) {
        this.FOnInvalidateRect = val;
    }
}

THCStyle.Null = -1,
THCStyle.Image = -2,
THCStyle.Table = -3,
THCStyle.Tab = -4,
THCStyle.Line = -5,
THCStyle.Express = -6,
THCStyle.Vector = -7,
THCStyle.Domain = -8,
THCStyle.PageBreak = -9,
THCStyle.CheckBox = -10,
THCStyle.Gif = -11,
THCStyle.Control = -12,
THCStyle.Edit = -13,
THCStyle.Combobox = -14,
THCStyle.QRCode = -15,
THCStyle.BarCode = -16,
THCStyle.Fraction = -17,
THCStyle.DateTimePicker = -18,
THCStyle.RadioGroup = -19,
THCStyle.SupSubScript = -20,
THCStyle.FloatLine = -101,
THCStyle.FloatBarCode = -102,
THCStyle.Custom = -1000;